package org.xx.armory.rpc.decorators;

import org.xx.armory.bindings.BoundParamCollection;
import org.xx.armory.rpc.Decorator;
import org.xx.armory.security.AuthenticationToken;
import org.xx.armory.service.Invocation;
import org.xx.armory.service.ServiceContext;
import org.xx.armory.service.ServiceNotAccessibleException;

import static org.xx.armory.service.ServiceContext.ROUTE_KEY;

/**
 * 验证授权的修饰器。
 */
public abstract class AbstractAuthorizationDecorator
        extends AbstractDecorator
        implements Decorator {
    /**
     * {@inheritDoc}
     *
     * 在执行方法之前检查当前登录用户是否具有此方法的权限。
     */
    @Override
    protected final void before(
            Invocation invocation,
            BoundParamCollection params,
            ServiceContext serviceContext
    )
            throws Exception {
        super.before(invocation, params, serviceContext);

        final AuthenticationToken token = serviceContext.getToken();
        final int[] permissions = invocation.getPermission();

        if (permissions.length == 0) {
            // 未指定权限数组，允许访问。
            return;
        }

        if (!isPermitted(token, permissions)) {
            // 当前登录用户不具备指定的权限，禁止访问。
            throw new ServiceNotAccessibleException("cannot access " + serviceContext.get(ROUTE_KEY));
        }
    }

    /**
     * 判断指定的令牌是否具有指定的权限。
     *
     * @param token
     *         令牌
     * @param permissions
     *         指定的权限。
     * @return 如果具有指定的权限则返回{@code true}，否则返回{@code false}。
     * @throws IllegalArgumentException
     *         如果参数{@code token}是{@code null}或者参数{@code permissions}是{@code null}或者长度为0。
     */
    protected abstract boolean isPermitted(
            AuthenticationToken token,
            int[] permissions
    )
            throws Exception;
}
